#pragma once
#include "loop_thread.hpp"
#include "acceptor.hpp"
#include "connection.hpp"
#include <signal.h>
namespace Muduo
{
    //对所有模块的整合
    class TcpServer
    {
    public:
        using ConnectionCallback = std::function<void(const Connection::PtrConnection&)>;
        using MessageCallback = std::function<void(const Connection::PtrConnection&,Buffer *)>;
        using ClosedCallback = std::function<void(const Connection::PtrConnection&)>;
        using AnyEventCallback = std::function<void(const Connection::PtrConnection&)>;
        TcpServer(int port):_port(port),_next_id(0),_enable_inactive_release(false),
        _acceptor(&_baseloop,port),_pool(&_baseloop)
        {
            _acceptor.SetAcceptCallback(std::bind(&TcpServer::NewConnection,this,std::placeholders::_1));
            _acceptor.Listen();//将监听套接字挂接到baseloop上
        }

        //设置从属线程池的数量
        void SetThreadCount(int count) 
        {
            _pool.SetThreadCount(count);
        }

        //设置回调函数
        void SetConnectedCallback(const ConnectionCallback & cb)
        {
            _connected_callback = cb;
        }

        void SetMessageCallback(const MessageCallback & cb)
        {
            _message_callback = cb;
        }

        void SetClosedCallback(const ClosedCallback & cb)
        {
            _closed_callback = cb;
        }

        void SetAnyEventCallback(const AnyEventCallback & cb)
        {
            _event_callback = cb;
        }

        //启动非活跃连接超时销毁功能
        void EnableInactiveRelease(int timeout)
        {
            _timeout = timeout;
            _enable_inactive_release = true;
        }

        //添加一个定时任务
        void RunAfter(const EventLoop::Functor &task,int delay)
        {
            _baseloop.RunInLoop(std::bind(&TcpServer::RunAfterInLoop,this,task,delay));
        }

        //启动服务器
        void Start()
        {
            _pool.Create();//创建线程池中的从属线程
            _baseloop.Start();
        }

    private:
        //添加用户的定时任务
        void RunAfterInLoop(const EventLoop::Functor & task,int delay)
        {
            _next_id++;
            _baseloop.TimerAdd(_next_id,delay,task);
        }

        //为新链接构造一个Connection进行管理
        void NewConnection(int fd)
        {
            _next_id++;
            Connection::PtrConnection conn(new Connection(_pool.NextLoop(),_next_id,fd));
            conn->SetMessageCallback(_message_callback);
            conn->SetClosedCallback(_closed_callback);
            conn->SetConnectedCallback(_connected_callback);
            conn->SetAnyEventCallback(_event_callback);
            conn->SetSrvClosedCallback(std::bind(&TcpServer::RemoveConnection,this,std::placeholders::_1));
            if(_enable_inactive_release) conn->EnableInactiveRelease(_timeout);//启动非活跃超时销毁
            conn->Established();//就绪初始化
            _conns.insert(std::make_pair(_next_id,conn));
        }

        //从管理连接的_conns中移除连接信息
        void RemoveConnectionInLoop(const Connection::PtrConnection & conn)
        {
            int id = conn->Id();
            auto it = _conns.find(id);
            if(it != _conns.end())
            {
                _conns.erase(it);
            }
        }

        //从管理Connection的_conn中移除连接信息
        void RemoveConnection(const Connection::PtrConnection & conn)
        {
            _baseloop.RunInLoop(std::bind(&TcpServer::RemoveConnectionInLoop,this,conn));
        }

    private:
        uint64_t _next_id; //自增的链接的id
        int _port;//端口号
        int _timeout;//多长时间无通信就是非活跃链接
        bool _enable_inactive_release;//是否启动了非活跃链接超时时间销毁
        EventLoop _baseloop;//实现对监听套接字的事件监控
        Accepter _acceptor;//监听套接字的管理对象
        LoopThreadPool _pool;//从属EventLoop线程池,对新建连接进行事件监控和处理
        std::unordered_map<uint64_t,Connection::PtrConnection> _conns;//保存管理所有链接对应的shared_ptr对象
        ConnectionCallback _connected_callback;//用户设置回调函数
        MessageCallback _message_callback;
        ClosedCallback _closed_callback;
        AnyEventCallback _event_callback;
    };

    //忽略掉SIGPIPE信号
    class NetWork
    {
    public:
        NetWork()
        {
            DLOG("SIGPIPE init");
            signal(SIGPIPE,SIG_IGN);
        }
    };
    static NetWork nw;
}